package futbol.tacticas.concursantes.TacticaTricolor;

import futbol.General;
import futbol.tacticas.*;
import futbol.tacticas.concursantes.Tactica;
import java.awt.Color;
import java.awt.Point;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Vector;


public class TacticaTricolor implements Tactica {

    private Point bolaTurnoAnterior = new Point(0, 0);
    private Point bolaTurnoSiguiente = new Point(0, 0);
    private int jugadoresTurnoSiguiente[][] = new int[11][2];
    private SituacionJugadores sj;
    Vector<Comando> comandos;
    int destinoPase = -1;
    private int nValores[][] = {
        // Golero
        {-150, 0, 4},
        // Defensas
        {-100, -75, 6},
        {-100, -15, 7},
        {-100, 15, 6},
        {-100, 75, 7},
        // Medios
        {-20, -60, 6},
        {-20, 0, 6},
        {-20, 60, 6},
        // Delanteros
        {80, -60, 7},
        {80, 60, 7},
        {90, 0, 7}
    };

    public String getNombre() {
        return "Tricolor";
    }

    public Color getColor1() {
        return Color.WHITE;
    }

    public Color getColor2() {
        return Color.BLUE;
    }

    public Color getColorNumero() {
        return Color.RED;
    }

    public int getFuerza(int n) {
        return nValores[n][2];
    }

    public int getXInicial(int n) {
        return nValores[n][0];
    }

    public int getYInicial(int n) {
        return nValores[n][1];
    }

    public Vector<Comando> getComandos(SituacionJugadores sj) {
        this.sj = sj;
        comandos = new Vector();

        setBolaSiguienteUbicacion();

        moverGolero();
        ArrayList<Integer> excluir = new ArrayList<Integer>();
        ArrayList<Integer> marcados = new ArrayList<Integer>();
        excluir.add(new Integer(0));
        excluir.add(new Integer(8));
        excluir.add(new Integer(9));
        excluir.add(new Integer(10));
        marcar(1, 4, -1, -40, -1, excluir, marcados);

        excluir.add(new Integer(1));
        excluir.add(new Integer(2));
        excluir.add(new Integer(3));
        excluir.add(new Integer(4));
        marcar(5, 7, -1, 40, -1, excluir, marcados);

        excluir = new ArrayList();
        excluir.add(new Integer(0));
        excluir.add(new Integer(1));
        excluir.add(new Integer(2));
        excluir.add(new Integer(3));
        excluir.add(new Integer(4));
        excluir.add(new Integer(5));
        excluir.add(new Integer(6));
        excluir.add(new Integer(7));
        marcar(8, 10, 50, 100, 50, excluir, marcados);

        destinoPase = -1;
        golpearBola();

        bolaTurnoAnterior.setLocation(sj.getBola());

        return comandos;
    }

    //agreguemos un valor para que si hay 2 o mas contrarios cerca entre si, los mios no marquen
    //asi no se amontonan.
    private void marcar(int desde, int hasta, int xDefensaDesde, int xDefensaHasta, double distanciaMaxima,
            ArrayList<Integer> excluirMarcador, ArrayList<Integer> marcados) {
        Point[] contrarios = sj.getContrario();
        int[] c = orderContrariosPorMenorX();
        for (int k = 0; k < c.length; k++) {
            int jugador = c[k];
            if (!marcados.contains(new Integer(jugador))) {
                Point contrario = contrarios[jugador];
                if ((xDefensaDesde == -1) || contrario.getX() > xDefensaDesde) {
                    if (contrario.getX() < xDefensaHasta) {
                        int marcador = getMiJugadorMasCerca(jugador, excluirMarcador);
                        if (marcador != -1) {
                            double distanciaAlContrario = General.getDistancia(nValores[marcador][0], nValores[marcador][1], contrario.getX(), contrario.getY());
                            if (distanciaMaxima == -1 || (distanciaAlContrario < distanciaMaxima)) {
                                boolean marcadoCerca = algunMarcadoCerca(marcados, jugador);
                                if (!marcadoCerca) {
                                    excluirMarcador.add(new Integer(marcador));
                                    marcados.add(new Integer(jugador));
                                    Point nuevaPosicion = getPosicionOptima(bolaTurnoSiguiente.getX(),
                                            bolaTurnoSiguiente.getY(), contrario.getX(),
                                            contrario.getY(), 10);
                                    moverJugador(marcador, nuevaPosicion.getX(), nuevaPosicion.getY());
                                }
                            }
                        }
                    }
                }
            }
        }

        //Los que no marcaron van a su posicion original, salvo que esten cerca del balon
        for (int i = desde; i <= hasta; i++) {
            if ((sj.getMasCercanoDeBola() == i) || sj.getMiJugadorMasCerca(bolaTurnoSiguiente.getX(), bolaTurnoSiguiente.getY()) == i) {
                moverJugador(i, bolaTurnoSiguiente.getX(), bolaTurnoSiguiente.getY());
            } else {
                if (!excluirMarcador.contains(new Integer(i))) {
                    Point nuevaPosicion = getPosicionOptima(bolaTurnoSiguiente.getX(),
                            bolaTurnoSiguiente.getY(), nValores[i][0], nValores[i][1], 20);
                    moverJugador(i, nuevaPosicion.getX(), nuevaPosicion.getY());
                }
            }
        }
    }

    private void golpearBola() {
        for (int i = 1; i <= 10; i++) {
            if (puedeSerGol(i)) {
                comandos.add(new ComandoTiroAPuerta(i, 0));
            } else {
                int siguienteJugador = pasarA(i);
                if (siguienteJugador != -1) {
                    pasarBola(i, siguienteJugador);
                } else {
                    comandos.add(new ComandoTiroAPuerta(i, 0));
                }
            }
        }
    }
    private int xMaximoGolero = -90; //para que no salga mucho


    private void moverGolero() {
        Point golero = sj.getMisJugadores()[0];
        if ((sj.getMasCercanoDeBola() == 0 ||
                sj.getMiJugadorMasCerca(bolaTurnoSiguiente.getX(), bolaTurnoSiguiente.getY()) == 0) &&
                bolaTurnoSiguiente.getX() < xMaximoGolero) {
            moverJugador(0, bolaTurnoSiguiente.getX(), bolaTurnoSiguiente.getY());
        } else {
            if (bolaTurnoSiguiente.getX() < xMaximoGolero && bolaTurnoSiguiente.getY() < 50 && bolaTurnoSiguiente.getY() > -50) {
                double x = bolaTurnoSiguiente.getX();
                if (x <= -155) {
                    x = nValores[0][0];
                }
                moverJugador(0, x, bolaTurnoSiguiente.getY());
            } else {
                int y = 0;
                if (bolaTurnoSiguiente.getY() < -20) {
                    y = -15;
                } else if (bolaTurnoSiguiente.getY() > 20) {
                    y = 15;
                }
                moverJugador(0, nValores[0][0], y);
            }
        }

        int y = -120;
        if (sj.getContrario()[sj.getContrarioMasCerca(0)].getY() <= golero.getY()) {
            y = 120;
        }
        comandos.add(new ComandoGolpearBola(0, golero.getX() + 80, y));
    }

    /************************************************/
    private void moverJugador(int jugador, double x, double y) {
        jugadoresTurnoSiguiente[jugador][0] = new Integer(String.valueOf(Math.round(x)));
        jugadoresTurnoSiguiente[jugador][1] = new Integer(String.valueOf(Math.round(y)));
        comandos.add(new ComandoIrA(jugador, x, y));
    }

    private Point getPosicionOptima(double x1, double y1, double x2, double y2, double distancia) {
        Point result = new Point();
        double x = getXParaMarcar(x1, y1, x2, y2, distancia);
        double y = getYOptimo(x1, y1, x2, y2, x);
        result.setLocation(x, y);
        return result;
    }

    private static double getYOptimo(double x1, double y1, double x2, double y2, double nuevoX) {
        double m = (y1 - y2) / (x1 - x2);
        return (m * (nuevoX - x2)) + y2;
    }

    private static double getXParaMarcar(double x1, double y1, double x2, double y2, double distancia) {
        double result = 0;
        if (Math.abs(x1 - x2) > 5) {
            if (x1 > x2) {
                result = x2 + distancia;
            } else {
                result = x2 - distancia;
            }
        } else {
            result = x2;
        }
        return result;
    }

    private int pasarA(int jugador) {
        int resultado = -1;
        int siguiente = siguienteJugador(jugador, null);
        double[] distanciasAlContrario = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
        ArrayList<Integer> excluir = new ArrayList<Integer>();
        excluir.add(new Integer(jugador));
        while (siguiente != -1) {
            if (distanciaEntreMisJugadores(jugador, siguiente) > 20) {
                distanciasAlContrario[siguiente] = distanciaAlContrario(siguiente, sj.getContrarioMasCerca(siguiente));
            }
            excluir.add(new Integer(siguiente));
            int[] tmp = new int[excluir.size()];
            for (int i = 0; i < excluir.size(); i++) {
                tmp[i] = ((Integer) excluir.get(i)).intValue();
            }
            siguiente = siguienteJugador(jugador, tmp);
        }
        double mayorDistancia = 0;

        for (int i = 0; i < distanciasAlContrario.length; i++) {
            double d = distanciasAlContrario[i];
            if (d >= mayorDistancia) {
                double dMisJugadores = distanciaEntreMisJugadores(jugador, i);
                if (resultado == -1 || dMisJugadores < 200) { //evitamos hacer pases tan largos

                    resultado = i;
                }
            }
        }
        return resultado;
    }

    private double distanciaEntreMisJugadores(int i, int j) {
        return General.getDistancia(sj.getMisJugadores()[i].getX(), sj.getMisJugadores()[i].getY(),
                sj.getMisJugadores()[j].getX(), sj.getMisJugadores()[j].getY());
    }

    private double distanciaAlContrario(int i, int j) {
        double distancia = General.getDistancia(sj.getMisJugadores()[i].getX(), sj.getMisJugadores()[i].getY(),
                sj.getContrario()[j].getX(), sj.getContrario()[j].getY());
        return distancia;
    }

    private void pasarBola(int jugador, int jugadorDestino) {
        double distanciaALaPelota = General.getDistancia(sj.getMisJugadores()[jugador].getX(),
                sj.getMisJugadores()[jugador].getY(), sj.getBola().getX(), sj.getBola().getY());
        if (distanciaALaPelota <= 10 && destinoPase == -1) {
            destinoPase = jugadorDestino;
            //movemos el jugador a donde puede caer la bola con velocidad 15 o menos.
            Point p = getDestinoBola(jugador, jugadoresTurnoSiguiente[jugadorDestino][0], jugadoresTurnoSiguiente[jugadorDestino][1]);
            moverJugador(jugadorDestino, p.getX(), p.getY());
        }
        comandos.add(new ComandoGolpearBola(jugador, jugadoresTurnoSiguiente[jugadorDestino][0], jugadoresTurnoSiguiente[jugadorDestino][1]));
    }

    private int siguienteJugador(int jugador, int[] excluir) {
        int dev1[] = sj.getInfoMasCercano(sj.getMisJugadores(), sj.getMisJugadores()[jugador], excluir, true);
        int result = dev1[0];
        if (result != -1) {
            if (llegaAMasDe15(jugador, jugadoresTurnoSiguiente[result][0], jugadoresTurnoSiguiente[result][1])) {
                int[] excluir2 = new int[1];
                if (excluir != null) {
                    excluir2 = new int[excluir.length + 1];
                    for (int i = 0; i < excluir.length; i++) {//                    

                        excluir2[i] = excluir[i];
                    }
                }
                excluir2[excluir2.length - 1] = result;
                result = siguienteJugador(jugador, excluir2);
            }
        }
        return result;
    }

    private boolean puedeSerGol(int jugador) {
        return llegaAMasDe15(jugador, 160, 0);
    }

    private boolean llegaAMasDe15(int jugador, double x, double y) {
        //si en base a la fuerza y la distancia es gol.Entonces vamos a patear, si no buscamos pase
        boolean result = false;
        Point p = sj.getMisJugadores()[jugador];
        double distancia = General.getDistancia(p.getX(), p.getY(), x, y);
        double fuerza = nValores[jugador][2];
        double distanciaNecesaria = 0;
        for (double i = fuerza * 3; i >= 15; i--) {
            distanciaNecesaria += i;
        }
        result = distancia < distanciaNecesaria;
        return result;
    }

    private Point getDestinoBola(int jugador, double xDestinoGolpe, double yDestinoGolpe) {
        Point p = new Point();
        Point bola = sj.getBola();
        int fuerza = nValores[jugador][2];
        double ang = General.getAngulo(bola.getX(), bola.getY(),
                xDestinoGolpe, yDestinoGolpe);
        long suma = 0;

        for (long i = fuerza * 3; i >= 15; i--) {
            suma += i;
        }
        double xFuturo = Math.cos(ang) * suma + bola.getX();
        double yFuturo = Math.sin(ang) * suma + bola.getY();
        if (Math.abs(xFuturo) > 1000 || Math.abs(yFuturo) > 1000) {
            xFuturo = 0;
            yFuturo = 0;
        } else {
            if (yFuturo < -120) {
                yFuturo = -240 - yFuturo;
            }
            if (yFuturo > 120) {
                yFuturo = 240 - yFuturo;
            }

            if (xFuturo < -160) {
                xFuturo = -320 - xFuturo;
            }
            if (xFuturo > 160) {
                xFuturo = 320 - xFuturo;
            }
        }

        p.setLocation(xFuturo, yFuturo);
        return p;
    }

    private void setBolaSiguienteUbicacion() {
        Point p = new Point();
        long distancia = Math.round(General.getDistancia(bolaTurnoAnterior.getX(), bolaTurnoAnterior.getY(),
                sj.getBola().getX(), sj.getBola().getY())) - 1;
        double ang = General.getAngulo(bolaTurnoAnterior.getX(), bolaTurnoAnterior.getY(),
                sj.getBola().getX(), sj.getBola().getY());

        long suma = 0;

        for (long i = distancia; distancia >= 15; distancia--) {
            suma += i;
        }

        double xFuturo = Math.cos(ang) * suma + sj.getBola().getX();
        double yFuturo = Math.sin(ang) * suma + sj.getBola().getY();
        if (Math.abs(xFuturo) > 1000 || Math.abs(yFuturo) > 1000) {
            xFuturo = 0;
            yFuturo = 0;
        } else {
            if (yFuturo < -120) {
                yFuturo = -240 - yFuturo;
            }
            if (yFuturo > 120) {
                yFuturo = 240 - yFuturo;
            }

            if (xFuturo < -160) {
                xFuturo = -320 - xFuturo;
            }
            if (xFuturo > 160) {
                xFuturo = 320 - xFuturo;
            }
        }

        p.setLocation(xFuturo, yFuturo);

        bolaTurnoSiguiente = p;
    }

    private int getMiJugadorMasCerca(int contrario, ArrayList excluir) {
        int dev1[] = sj.getInfoMasCercano(sj.getMisJugadores(), sj.getContrario()[contrario], getIntArray(excluir), false);
        return dev1[0];
    }

    private int[] getIntArray(ArrayList arr) {
        int[] tmp = new int[arr.size()];
        for (int i = 0; i < arr.size(); i++) {
            tmp[i] = ((Integer) arr.get(i)).intValue();
        }
        return tmp;
    }

    private int[] orderContrariosPorMenorX() {
        ArrayList<Jugador> contrarios = new ArrayList<Jugador>(11);
        for (int i = 0; i <= 10; i++) {
            Jugador j = new Jugador();
            j.id = i;
            j.p = sj.getContrario()[i];
            contrarios.add(j);
        }
        Collections.sort(contrarios, new ComparadorContrario());

        int[] result = new int[11];
        for (int i = 0; i <= 10; i++) {
            result[i] = contrarios.get(i).id;
        }
        return result;
    }

    private boolean algunMarcadoCerca(ArrayList marcados, int aMarcar) {
        double distancia = 40;
        boolean result = false;
        for (int i = 0; i < marcados.size(); i++) {
            int marcado = ((Integer) marcados.get(i)).intValue();
            if (distancia > General.getDistancia(sj.getContrario()[marcado].getX(),
                    sj.getContrario()[marcado].getY(), sj.getContrario()[aMarcar].getX(),
                    sj.getContrario()[aMarcar].getY())) {
                result = true;
            }

        }
        return result;
    }
}
class ComparadorContrario implements Comparator {

    public int compare(Object o1, Object o2) {
        int result = new Double(((Jugador) o1).p.getX()).compareTo(new Double(((Jugador) o2).p.getX()));
        return result;
    }
}

class Jugador {

    public int id;
    public Point p;
}

